package com.company.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

import java.beans.PropertyVetoException;

/*
    声明式事务
    1 导入数据源 数据库驱动 Spring-jdbc模块
    2 配置数据源，jdbcTemplate（Spring提供的简化数据库的操作等工具）操作数据
    3 给方法上标上 @Transactional， 表示当前方法是一个事务方法
    4 @EnableTransactionManagement 开启基于注解的事务管理功能
    5 配置事务管理器控制事务在容器中

  原理
     1 @EnableTransactionManagement利用TransactionManagementConfigurationSelector给容器导入组件
          导入两个组件 AutoProxyRegister
                     ProxyTransactionManagementConfiguration
     2 AutoProxyRegister 给容器注册一个InfrastructureAdvisorAutoProxyCreator组件
             InfrastructureAdvisorAutoProxyCreator利用后置处理器机制在对象创建以后，包装对象，返回一个代理对象（增强器）
             代理对象执行方法利用拦截器链进行
     3  ProxyTransactionManagementConfiguration
             1 给容器注册事务增强器
                1  事务增强器要用事务注解信息 AnnotationTransactionAttributeSource 解析事务
                2  事务拦截器
                    TransactionInterceptor 保存了事务属性信息，事务管理器
                    他是一个方法拦截器 MethodInterceptor
                    在目标方法执行的时候
                        执行事务拦截器
                        事务拦截器
                           1 先获取事务的相关属性
                           2 在获取PlateformTransactionManager 如果事先没有添加，最终会从容器中按照类型获取
                           3 方法执行如果异常，获取到事务管理器，利用事务管理回滚
                             如果正常，利用事务管理器提交事务
 */
@Configuration
@ComponentScan("com.company")
@EnableTransactionManagement
public class TxConfig {
    private DataSource dataSource;

    @Bean
    public DataSource dataSource() throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("123456");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        this.dataSource = dataSource;
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) throws Exception {
        //Spring 对@Configuration类会特殊处理，给容器加组件的方法，多次调用会在容器中查找组件
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }

    //注册事务管理器在容器中
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}
